<template>
    <div class="canvas-draw-container">
        <canvas class="canvas-draw-content" :width=canvasSize.width :height=canvasSize.height></canvas>
        <ul class="canvas-draw-menu" :style="{
            left: menuStyle.left, top: menuStyle.top, width: menuStyle.width + 'px',
            height: menuStyle.height + 'px'
        }" v-show="isShowMenu">
            <li class="canvas-draw-menu-item">
                <button @click="showColorInput">颜色</button>
            </li>
            <li class="canvas-draw-menu-item">
                <button @click="btDrawCircle">绘制圆形</button>
            </li>
            <li class="canvas-draw-menu-item">
                <button @click="btDrawRectangle">绘制矩形</button>
            </li>
            <li class="canvas-draw-menu-item">
                <button @click="btDrawLine">自由线</button>
            </li>
            <li class="canvas-draw-menu-item">
                <button @click="clearCanvas">清空</button>
            </li>
            <li class="canvas-draw-menu-item">
                <button @click="downImg">下载</button>
            </li>
        </ul>
        <input id="canvas-draw-color-input" type="color" @change="changeColor" value="#ffffff" v-show="isShowColorInput"
            :style="{ left: inputPosition.left, top: inputPosition.top }">
        <div id="canvas-draw-select" v-show="isShowDrawSelect" :style="{
            left: selectStyle.left, top: selectStyle.top, width: selectStyle.width,
            height: selectStyle.height, borderRadius: selectStyle.borderRadius
        }">
        </div>
        <div class="canvas-draw-imgbox" v-show="isShowImg">
            <img id="canvas-draw-img" :src="dataUrl">
        </div>
    </div>
</template>

<script>
export default {
    name: "CanvasDraw",
    data() {
        return {
            isShowMenu: false,
            isShowColorInput: false,
            isShowDrawSelect: false,
            isDrawing: false,
            isShowImg: false,
            strokeColor: "#ffffff",
            menuStyle: {
                left: "0px",
                top: "0px",
                width: 100,
                height: 310,
            },
            inputPosition: {
                left: "0px",
                top: "0px",
            },
            downX: 0,
            downY: 0,
            drawLine: "LINE",
            drawCircle: "CIRCLE",
            drawRectangle: "RECTANGLE",
            drawType: "LINE",
            lastDrawTime: 0,
            selectStyle: {
                left: "",
                top: "",
                width: "",
                height: "",
                borderRadius: "",
            },
            canvasSize: {
                width: 0,
                height: 0,
            },
            canvas: null,
            canvasCtx: null,
            dataUrl: null,
        }
    },
    computed: {

    },
    methods: {
        //绘制
        draw(event) {
            const current = Date.now();
            if (current - this.lastDrawTime < 10) {//绘制时间间隔
                return;
            }
            this.lastDrawTime = current;

            const x = event.layerX;
            const y = event.layerY;

            let left = 0;
            let top = 0;
            let width = 0;
            let height = 0;
            switch (this.drawType) {
                case this.drawLine:
                    this.canvasCtx.lineTo(x, y);
                    this.canvasCtx.stroke();
                    break;
                case this.drawCircle:
                    //鼠标与div之间间隔20，防止div遮挡鼠标事件
                    width = x - this.downX;
                    height = y - this.downY;
                    if (width === 0) {
                        break;
                    }

                    if (width < 0) {
                        width = -width;
                        left = x + 20;
                    } else {
                        left = x - width - 20;
                    }
                    if (height < 0) {
                        top = y + 20;
                    } else {
                        top = y - width - 20;
                    }

                    this.selectStyle.left = left + "px";
                    this.selectStyle.top = top + "px";
                    this.selectStyle.width = width + "px";
                    this.selectStyle.height = width + "px";
                    this.isShowDrawSelect = true;
                    break;
                case this.drawRectangle:
                    //鼠标与div之间间隔20，防止div遮挡鼠标事件
                    width = x - this.downX;
                    height = y - this.downY;
                    if (width === 0 || height === 0) {
                        break;
                    }

                    if (width < 0) {
                        width = -width;
                        left = x + 20;
                    } else {
                        left = x - width - 20;
                    }
                    if (height < 0) {
                        height = -height;
                        top = y + 20;
                    } else {
                        top = y - height - 20;
                    }

                    this.selectStyle.left = left + "px";
                    this.selectStyle.top = top + "px";
                    this.selectStyle.width = width + "px";
                    this.selectStyle.height = height + "px";
                    this.isShowDrawSelect = true;
                    break;
                default:
                    break;
            }
        },
        //创建圆形
        btDrawCircle() {
            this.drawType = this.drawCircle;
            this.isShowMenu = false;

            this.selectStyle.borderRadius = "50%";
            this.selectStyle.left = "0px";
            this.selectStyle.top = "0px";
            this.selectStyle.width = "0px";
            this.selectStyle.height = "0px";
        },
        //创建矩形
        btDrawRectangle() {
            this.drawType = this.drawRectangle;
            this.isShowMenu = false;

            this.selectStyle.borderRadius = "0";
            this.selectStyle.left = "0px";
            this.selectStyle.top = "0px";
            this.selectStyle.width = "0px";
            this.selectStyle.height = "0px";
        },
        //自由线绘制
        btDrawLine() {
            this.drawType = this.drawLine;
            this.isShowMenu = false;
        },

        //修改笔触颜色
        showColorInput() {
            this.isShowMenu = false;
            this.inputPosition.left = this.menuStyle.left;
            this.inputPosition.top = this.menuStyle.top;
            this.isShowColorInput = true;
        },

        changeColor(event) {
            this.strokeColor = event.target.value;
        },

        //清空
        clearCanvas() {
            this.isShowMenu = false;
            this.canvasCtx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);
        },

        //下载
        downImg() {
            this.isShowImg = true;
            this.dataUrl = this.canvas.toDataURL();
        },

        //右键菜单
        showMenu(event) {
            this.isShowColorInput = false;
            event.preventDefault();

            // 鼠标相比较于当前坐标系的位置,即如果触发元素没有设置绝对定位或相对定位,以页面为参考点,如果有,将改变参考坐标系,
            // 从触发元素盒子模型的border区域的左上角为参考点
            let left = event.layerX;
            let top = event.layerY;

            //超过边界修改位置
            if (left + this.menuStyle.width > this.canvasSize.width) {
                left = left - this.menuStyle.width;
            }
            if (top + this.menuStyle.height > this.canvasSize.height) {
                top = top - this.menuStyle.height;
            }

            this.menuStyle.left = left + "px";
            this.menuStyle.top = top + "px";
            this.isShowMenu = true;
        },
        //按下鼠标左键
        downMouse(event) {
            let isLeftMB = false;
            let isRightMB = false;
            if ("which" in event) {
                isRightMB = event.which == 3;
                isLeftMB = event.which == 1;
            }
            else if ("button" in event) {
                isRightMB = e.button == 2;
                isLeftMB = e.button == 0;
            }
            if (!isLeftMB) {//不是左键被按下
                return;
            }
            if (this.isShowMenu || this.isShowColorInput || this.isShowImg) {
                this.isShowMenu = false;
                this.isShowColorInput = false;
                this.isShowImg = false;
                return;
            }

            this.isDrawing = true;

            // 鼠标相比较于当前坐标系的位置,即如果触发元素没有设置绝对定位或相对定位,以页面为参考点,如果有,将改变参考坐标系,
            //从触发元素盒子模型的border区域的左上角为参考点
            this.downX = event.layerX;
            this.downY = event.layerY;

            //当前线条的宽度
            this.canvasCtx.lineWidth = 5;
            //线条末端线帽的样式
            this.canvasCtx.lineCap = "round";
            //当两条线交汇时,创建边角的类型
            this.canvasCtx.lineJoin = "round";
            //笔触的颜色
            this.canvasCtx.strokeStyle = this.strokeColor;
            // 定义一个新路径：
            this.canvasCtx.beginPath();
            // 定义起点：
            this.canvasCtx.moveTo(this.downX, this.downY);

            //监听鼠标移动
            this.canvas.addEventListener("mousemove", this.draw);
        },

        //松开鼠标左键
        upMouse(event) {
            let isLeftMB = false;
            let isRightMB = false;
            if ("which" in event) {
                isRightMB = event.which == 3;
                isLeftMB = event.which == 1;
            }
            else if ("button" in event) {
                isRightMB = e.button == 2;
                isLeftMB = e.button == 0;
            }
            if (!isLeftMB) {//不是左键松开
                return;
            }
            if (!this.isDrawing) {
                return;
            }

            const x = event.layerX;
            const y = event.layerY;

            switch (this.drawType) {
                case this.drawCircle:
                    let r = (x - this.downX) / 2;
                    let cx = x - r;
                    let cy = y - r;

                    if (r === 0) {
                        break;
                    }

                    if (x - this.downX < 0) {
                        r = -r;
                        cx = x + r + 20;
                    } else {
                        cx = x - r - 20;
                    }
                    if (y - this.downY < 0) {
                        cy = y + r + 20;
                    } else {
                        cy = y - r - 20;
                    }

                    //绘制圆形
                    this.canvasCtx.beginPath();
                    this.canvasCtx.arc(cx, cy, r, 0, 2 * Math.PI);
                    this.canvasCtx.stroke();
                    this.isShowDrawSelect = false;
                    break;
                case this.drawRectangle:
                    let rx = x;
                    let ry = y;

                    let w = x - this.downX;
                    let h = y - this.downY;
                    if (w === 0 || h === 0) {
                        break;
                    }
                    if (w < 0) {
                        w = -w;
                        rx = x + 20;
                    } else {
                        rx = x - w - 20;
                    }
                    if (h < 0) {
                        h = -h;
                        ry = y + 20;
                    } else {
                        ry = y - h - 20;
                    }
                    //绘制矩形
                    this.canvasCtx.rect(rx, ry, w, h);
                    this.canvasCtx.stroke();
                    this.isShowDrawSelect = false;
                    break;
                default:
                    break;
            }
            this.isDrawing = false;

            this.canvas.removeEventListener("mousemove", this.draw);
        }

    },
    created() {

    },
    mounted() {
        const container = this.$el;
        this.canvas = this.$el.querySelector(".canvas-draw-content");
        //初始化画布大小
        this.canvasSize.width = container.offsetWidth;
        this.canvasSize.height = container.offsetHeight;
        this.canvasCtx = this.canvas.getContext("2d");

        this.canvas.addEventListener("contextmenu", this.showMenu);
        this.canvas.addEventListener("mousedown", this.downMouse);
        this.canvas.addEventListener("mouseup", this.upMouse);
    },
    beforeUnmount() {
        if(this.canvas){
            this.canvas.removeEventListener("contextmenu", this.showMenu);
            this.canvas.removeEventListener("mousedown", this.downMouse);
            this.canvas.removeEventListener("mouseup", this.upMouse);
        }
    }
}
</script>

<style scoped>
.canvas-draw-container {
    width: 100%;
    height: 100%;
    position: relative;
}

.canvas-draw-content {
    width: 100%;
    height: 100%;
    position: absolute;
    background-color: #222;
    background-image: linear-gradient(to right, #333 1px, transparent 1px), linear-gradient(to bottom, #333 1px, transparent 1px);
    background-size: 40px 40px;
}

.canvas-draw-menu {
    position: absolute;
    background-color: rgb(162, 145, 122);
    border-radius: 5px;
    margin: 0;
    padding: 10px;
}

.canvas-draw-menu-item {
    width: 80px;
    height: 40px;
    margin: 10px;
    list-style: none;
}

.canvas-draw-menu-item>button {
    background-color: transparent;
    width: 100%;
    height: 100%;
    font-size: 15px;
    color: rgb(240, 243, 246);
}

#canvas-draw-color-input {
    position: absolute;
    width: 100px;
    height: 40px;
}

#canvas-draw-select {
    position: absolute;
    border: dashed 2px #c41a1a;
}

.canvas-draw-imgbox {
    position: absolute;
    width: 50%;
    height: 50%;
    left: 25%;
    top: 25%;
    background-color: #000000;
}

#canvas-draw-img {
    width: 90%;
    height: 90%;
}
</style>
